home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xarchie-2.0.9
/
query.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-18
|
13KB
|
441 lines
/*
* query.c : Programmatic Prospero interface to Archie
*
* Copyright (c) 1991 by the University of Washington
*
* For copying and distribution information, please see the file
* <copyright.h>.
*
* Originally part of the Prospero Archie client by Clifford
* Neuman (bcn@isi.edu). Modifications, addition of programmatic interface,
* and new sorting code by George Ferguson (ferguson@cs.rochester.edu)
* and Brendan Kehoe (brendan@cs.widener.edu).
*
* v2.0 - 04/23/93 (gf) - for xarchie 2.0 - and now we part company...
* v1.3.2 - bpk - for Archie client 1.3.2
* v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
* v1.1.3 - 08/30/91 (bpk) - cast index()
* v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink)
* v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does
*/
#include <copyright.h>
#include <stdio.h>
#include <pfs.h>
#include <perrno.h>
#include <archie.h>
#include "config.h"
#ifdef TM_IN_SYS_TIME
# include <sys/time.h>
#else
# include <time.h>
#endif
#include "stringdefs.h"
#include "xtypes.h"
#include "db.h"
#include "appres.h"
#include "browser.h"
#include "alert.h"
#include "status.h"
#include "debug.h"
extern DbEntry *db;
/* These are in dirsend.c */
extern int client_dirsrv_timeout,client_dirsrv_retry,rdgram_priority;
/* Functions defined here: */
void queryItemAndParse(),queryHostAndParse(),queryLocationAndParse();
VLINK stringQuery();
int parseArchieQueryResults(), parseStringQueryResults();
int handleProsperoErrors();
static void doQueryAndParse();
static void parseHostAndFilename(), parseAttributes();
/* Data defined here */
int pfs_debug;
/* - - - - - - - - */
/*
* Main function to call to process a query from the user.
*/
void
queryItemAndParse(query)
char *query;
{
char qstring[MAX_VPATH];
DEBUG1("queryItemAndParse: \"%s\"\n",query);
sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
appResources.maxHits,appResources.offset,appResources.searchType,
query);
doQueryAndParse(qstring);
DEBUG0("queryItemAndParse: done\n");
}
/*
* Main function to open a host specified by the user.
*/
void
queryHostAndParse(hostname)
char *hostname;
{
char qstring[MAX_VPATH];
DEBUG1("queryHostAndParse: \"%s\"\n",hostname);
sprintf(qstring,"ARCHIE/HOST/%s",hostname);
doQueryAndParse(qstring);
DEBUG0("queryHostAndParse: done\n");
}
/*
* Main function to open a host specified by the user.
*/
void
queryLocationAndParse(hostname,location)
char *hostname,*location;
{
char qstring[MAX_VPATH];
DEBUG2("queryLocationAndParse: \"%s:%s\"\n",hostname,location);
sprintf(qstring,"ARCHIE/HOST/%s%s",hostname,location);
doQueryAndParse(qstring);
DEBUG0("queryLocationAndParse: done\n");
}
/*
* Used by both query functions to send the string to Archie and interpret
* the results into the browser.
*/
static void
doQueryAndParse(str)
char *str;
{
VLINK links;
int num;
/* Send the query to Archie */
DEBUG1("doQueryAndParse: \"%s\"\n",str);
DEBUG0("calling stringQuery...\n");
links = stringQuery(appResources.archieHost,str);
DEBUG0("calling handleProsperoErrors...\n");
(void)handleProsperoErrors();
/* If we aborted or had an error, then don't clear the db */
if (links == NULL ) {
/* Wasn't an error... */
if (perrno == PSUCCESS)
status0("No matches -- Ready.");
return;
}
/* Reset browser to leftmost position */
resetBrowser();
/* Empty (and free) previous contents of database */
clearEntries(db);
/* Process the results into the database */
status0("Parsing...");
DEBUG0("calling parseArchieQueryResults\n");
switch(appResources.sortType) {
case GfName:
num = parseArchieQueryResults(db,links,cmpEntryNames);
break;
case GfDate:
num = parseArchieQueryResults(db,links,cmpEntryDates);
break;
case GfWeight:
num = parseArchieQueryResults(db,links,cmpEntryWeights);
break;
}
/* Display results in browser */
DEBUG0("calling displayEntries\n");
displayEntries(db,0);
status1("Found %d matches -- Ready",(char *)num);
DEBUG0("doQueryAndParse: done\n");
}
/* - - - - - - - - */
/*
* Returns an unsorted, untranslated list of vlinks for string from host.
*/
VLINK
stringQuery(host,string)
char *host,*string;
{
VLINK links; /* Matches returned by server */
VDIR_ST dir_st; /* Filled in by get_vdir */
PVDIR dir = &dir_st;
VLINK p,nextp,r;
int tmp;
/* initialize Prospero globals from appResources */
pfs_debug = appResources.debugLevel;
rdgram_priority = appResources.niceLevel;
client_dirsrv_timeout = appResources.timeout;
client_dirsrv_retry = appResources.retries;
/* Initialize Prospero structures */
perrno = PSUCCESS; *p_err_string = '\0';
pwarn = PNOWARN; *p_warn_string = '\0';
vdir_init(dir);
/* Retrieve the list of matches, return error if there was one */
#if defined(MSDOS)
if ((tmp=get_vdir(host,string,"",dir,
(long)GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) != 0) {
#else
if ((tmp=get_vdir(host,string,"",dir,
GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) != 0) {
# endif
perrno = tmp;
return(NULL);
}
/* Save the links, and clear in dir in case it's used again */
links = dir->links; dir->links = NULL;
/* As returned, list is sorted by suffix, and conflicting */
/* suffixes appear on a list of "replicas". We want to */
/* create a one-dimensional list sorted by host then filename */
/* and maybe by some other parameter */
/* First flatten the doubly-linked list */
for (p = links; p != NULL; p = nextp) {
nextp = p->next;
if (p->replicas != NULL) {
p->next = p->replicas;
p->next->previous = p;
for (r = p->replicas; r->next != NULL; r = r->next)
/*EMPTY*/ ;
r->next = nextp;
nextp->previous = r;
p->replicas = NULL;
}
}
perrno = PSUCCESS;
return(links);
}
/* - - - - - - - - */
/*
* Here take the list of untranslated unsorted links and put them into the
* database, translating and sorting as needed. The entries are added to
* make a host-location-file hierarchy as appropriate for the top of the
* database query for a query. Returns number of entries returned from query.
* This routine is also used by the routine that reloads a database.
*/
int
parseArchieQueryResults(parent,links,cmp_proc)
DbEntry *parent;
VLINK links;
int (*cmp_proc)();
{
VLINK vl;
DbEntry *firstHost,*firstLoc;
DbEntry *thisHost,*thisLoc,*thisFile;
char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
int type;
#ifdef MSDOS
unsigned long size;
#else
int size;
#endif
char *modes,*gt_date,*archie_date;
int num;
DEBUG0("parseArchieQueryResults: parsing links...\n");
num = 0;
firstHost = firstLoc = NULL;
for (vl=links; vl != NULL; vl = vl->next) {
parseHostAndFilename(vl,hostname,location,filename);
parseAttributes(vl,&type,&size,&modes,&archie_date,>_date);
if (firstHost == NULL) {
firstHost = thisHost = addEntry(parent,NULL);
firstLoc = thisLoc = addEntry(firstHost,NULL);
thisFile = addEntry(firstLoc,NULL);
} else {
if ((thisHost=findEntryFromString(parent,hostname)) == NULL)
thisHost = addEntry(parent,NULL);
if ((thisLoc=findEntryFromString(thisHost,location)) == NULL)
thisLoc = addEntry(thisHost,NULL);
thisFile = addEntry(thisLoc,NULL);
}
setEntryData(thisHost,hostname,DB_HOST,0,"","","",NULL);
setEntryData(thisLoc,location,DB_LOCATION,0,"","","",NULL);
setEntryData(thisFile,filename,type,size,modes,archie_date,gt_date,vl);
num += 1;
}
DEBUG0("parseArchieQueryResults: sorting entries...\n");
sortEntriesRecursively(parent,cmp_proc);
DEBUG1("parseArchieQueryResults: returning %d matches\n",num);
return(num);
}
/*
* Like parseArchieQueryresults(), but all the entries for the links are
* added as immediate children of parent, rather than a three-level tree.
* This is used to expand the browser below some item.
*/
int
parseStringQueryResults(parent,links,cmp_proc)
DbEntry *parent;
VLINK links;
int (*cmp_proc)();
{
VLINK vl;
DbEntry *dbp;
char hostname[MAX_VPATH],location[MAX_VPATH],filename[MAX_VPATH];
int type,size;
char *modes,*gt_date,*archie_date;
int num;
DEBUG0("parseStringQueryResults: parsing links...\n");
num = 0;
for (vl=links; vl != NULL; vl = vl->next) {
parseHostAndFilename(vl,hostname,location,filename);
parseAttributes(vl,&type,&size,&modes,&archie_date,>_date);
dbp = addEntry(parent,NULL);
setEntryData(dbp,filename,type,size,modes,archie_date,gt_date,vl);
num += 1;
}
DEBUG0("parseStringQueryResults: sortign entries...\n");
sortEntriesRecursively(parent,cmp_proc);
DEBUG1("parseStringQueryResults: returning %d matches\n",num);
return(num);
}
/*
* Fills in hostname, location, and filename with the appropriately-translated
* and adjusted information from the link vl.
*/
static void
parseHostAndFilename(vl,hostname,location,filename)
VLINK vl;
char *hostname,*location,*filename;
{
char *slash;
DEBUG3(" input:host=\"%s\"\n filename=\"%s\"\n name=\"%s\"\n",
vl->host,vl->filename,vl->name);
/* If the link is for an Archie pseudo-directory, adjust names. */
if (strcmp(vl->type,"DIRECTORY") == 0 &&
strncmp(vl->filename,"ARCHIE/HOST",11) == 0) {
strcpy(hostname,vl->filename+12);
slash = index(hostname,'/');
if (slash != NULL) {
strcpy(filename,slash);
*slash = '\0';
} else
strcpy(filename,"/");
} else {
/* else just use the names as is */
strcpy(hostname,vl->host);
strcpy(filename,vl->filename);
}
/* The "location" is the leading part of the pathname */
strcpy(location,filename);
slash = rindex(location,'/');
/* If filename ends with slash, try going back one more slash */
if (slash && *(slash+1) == '\0')
slash = (char *)rindex(slash,'/');
if (slash) {
strcpy(filename,slash+1);
*slash = '\0';
} else
strcpy(location,"/");
/* If filename was /foo, then we need to leave the slash there */
if (*location == '\0')
strcpy(location,"/");
DEBUG3(" output:host=\"%s\"\n location=\"%s\"\n filename=\"%s\"\n",
hostname,location,filename);
}
/*
* Fills in *sizep, *modesp, and archie_date with the information in the
* attribute list of the link vl.
*/
static void
parseAttributes(vl,typep,sizep,modesp,archie_datep,gt_datep)
VLINK vl;
int *typep;
#ifdef MSDOS
unsigned long *sizep;
#else
int *sizep;
#endif
char **modesp,**archie_datep,**gt_datep;
{
static char date[64];
PATTRIB ap;
int gt_year,gt_mon,gt_day,gt_hour,gt_min;
struct tm *presenttime;
long now;
(void)time(&now);
presenttime = localtime(&now);
if (strcmp(vl->type,"DIRECTORY") == 0) {
*typep = DB_DIRECTORY;
} else {
*typep = DB_FILE;
}
*sizep = 0;
*modesp = "";
*archie_datep = "";
*gt_datep = "";
gt_year = gt_mon = gt_day = gt_hour = gt_min = 0;
for (ap = vl->lattrib; ap; ap = ap->next) {
if (strcmp(ap->aname,"SIZE") == 0) {
#ifdef MSDOS
sscanf(ap->value.ascii,"%lu",sizep);
#else
sscanf(ap->value.ascii,"%d",sizep);
#endif
} else if(strcmp(ap->aname,"UNIX-MODES") == 0) {
*modesp = ap->value.ascii;
} else if(strcmp(ap->aname,"LAST-MODIFIED") == 0) {
*gt_datep = ap->value.ascii;
sscanf(*gt_datep,"%4d%2d%2d%2d%2d",>_year,
>_mon, >_day, >_hour, >_min);
if ((12 * (presenttime->tm_year + 1900 - gt_year) +
presenttime->tm_mon - gt_mon) > 6)
sprintf(date,"%s %2d %4d",month_sname(gt_mon),
gt_day, gt_year);
else
sprintf(date,"%s %2d %02d:%02d",month_sname(gt_mon),
gt_day, gt_hour, gt_min);
*archie_datep = date;
}
}
}
/*
* Pops up alerts depending on perrno and pwarn.
* Used in several places after calling Archie.
*/
int
handleProsperoErrors()
{
int err = 0;
/* Error? */
if (perrno != PSUCCESS) {
if (p_err_text[perrno]) {
if (*p_err_string)
alert2("Prospero error: %.100s - %.100s",p_err_text[perrno],
p_err_string);
else
alert1("Prospero error: %.200s",p_err_text[perrno]);
} else
alert1("Prospero error: Undefined error %d (prospero)",(char*)perrno);
err = 1;
}
/* Warning? */
if (pwarn != PNOWARN) {
if (*p_warn_string)
alert2("Prospero warning: %.100s - %.100s",
p_warn_text[pwarn], p_warn_string);
else
alert1("Prospero warning: %.200s",p_warn_text[pwarn]);
status0("Ready");
}
return(err);
}